package com.hydra.auth.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.hydra.base.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDate;
import java.util.*;

@Slf4j
public class RSAUtil {

    public static final String CHARSET = "UTF-8";
    //密钥算法
    public static final String ALGORITHM_RSA = "RSA";
    //RSA 签名算法
    public static final String ALGORITHM_RSA_SIGN = "SHA256WithRSA";

    public static final int ALGORITHM_RSA_PRIVATE_KEY_LENGTH = 2048;

    /**
     * RSA算法使用私钥对数据生成数字签名
     *
     * @param data 待签名的明文字符串
     * @param key  RSA私钥字符串
     * @return RSA私钥签名后的经过Base64编码的字符串
     */
    public static String buildRSASignByPrivateKey(String data, String key) {
        try {
            //通过PKCS#8编码的Key指令获得私钥对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(ALGORITHM_RSA_SIGN);
            signature.initSign(privateKey);
            signature.update(data.getBytes(CHARSET));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException("签名字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * RSA算法使用公钥校验数字签名
     *
     * @param data 参与签名的明文字符串
     * @param key  RSA公钥字符串
     * @param sign RSA签名得到的经过Base64编码的字符串
     * @return true--验签通过,false--验签未通过
     */
    public static boolean verifySignStrByPublicKey(String data, String key, String sign) {
        try {
            //通过X509编码的Key指令获得公钥对象
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
            PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
            Signature signature = Signature.getInstance(ALGORITHM_RSA_SIGN);
            signature.initVerify(publicKey);
            signature.update(data.getBytes(CHARSET));
            return signature.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e) {
            throw new RuntimeException("验签字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 初始化RSA算法密钥对
     * @return 经过Base64编码后的公私钥Map, 键名分别为publicKey和privateKey
     */
    public static Map<String, String> initRSAKey() {
        //为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance(ALGORITHM_RSA);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("No such algorithm-->[" + ALGORITHM_RSA + "]");
        }
        //初始化KeyPairGenerator对象,不要被initialize()源码表面上欺骗,其实这里声明的size是生效的
        kpg.initialize(ALGORITHM_RSA_PRIVATE_KEY_LENGTH);
        //生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        //得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);
        return keyPairMap;
    }


    /**
     * 生成签名字符串
     * 按TreeSet的默认排序即可
     */
    public static String signatureStr(String parameters){
        StringBuilder tempStr = new StringBuilder();

        //将value放到 treeSet中排序，  采用默认排序即可
        TreeSet<String> values = new TreeSet<>();

        JSONObject jsonObject = JsonUtil.parseObject(parameters);
        Set<String> keySet = jsonObject.keySet();
        for (String key : keySet) {
            Object obj = jsonObject.get(key);
            if(obj != null){
                if(obj instanceof JSONArray){
                    JSONArray array = (JSONArray)obj;
                    for (Object subObj : array) {
                        String str;
                        if(subObj instanceof JSONObject){
                            JSONObject json = (JSONObject) subObj;
                            str = signatureStr(json.toJSONString());
                        }else{
                            str = String.valueOf(subObj);
                        }
                        values.add(str);
                    }
                }else if(obj instanceof JSONObject){
                    JSONObject json = (JSONObject) obj;
                    String str = signatureStr(json.toJSONString());
                    values.add(str);
                }else{
                    String str = String.valueOf(obj);
                    values.add(str);
                }
            }
        }
        // 排序并拼接参数值（按值的升序排序）
        for (String val : values) {
            if(StringUtils.isNotBlank(val)){
                tempStr.append(val);
            }
        }
        return tempStr.toString();
    }

    public static void main(String[] args) {
//        //生成RSA公私钥
//        Map<String, String> rsaKey = RSAUtil.initRSAKey();
//        log.info(JSON.toJSONString(rsaKey));

        String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoURsmCbSxmjX4WZtEAvaQfQe85z81JeGOsusj1n2VpeSGdbwRJSM3xxjXQDIesWrN+JirWFbC14lp0nkCnPbuBvjK2ZZ7TWhkB04QLIGp4RgehmAUeoI6YhPGLaHm4umvCc0bv0UE6COMas8PWnFj2YmKl7Qz7alOozB4Pqnfxe57LMGxeoSN/zN2UAMYbP+8Y9QqH0Qq46OshbRG8v8MR94XMBx1uf2CshHg2EFzqx48Q2wXKXGUhRhr2K39eAVGQ5wRHP/K9qpFar5kLwDSonPWjtyDbOXC2/MYyu2FIUeDsSKe9joMxfhLNRt/CqK0vspyFM1eTG1i/XR7cWRgwIDAQAB";
        String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQChRGyYJtLGaNfhZm0QC9pB9B7znPzUl4Y6y6yPWfZWl5IZ1vBElIzfHGNdAMh6xas34mKtYVsLXiWnSeQKc9u4G+MrZlntNaGQHThAsganhGB6GYBR6gjpiE8Ytoebi6a8JzRu/RQToI4xqzw9acWPZiYqXtDPtqU6jMHg+qd/F7nsswbF6hI3/M3ZQAxhs/7xj1CofRCrjo6yFtEby/wxH3hcwHHW5/YKyEeDYQXOrHjxDbBcpcZSFGGvYrf14BUZDnBEc/8r2qkVqvmQvANKic9aO3INs5cLb8xjK7YUhR4OxIp72OgzF+Es1G38KorS+ynIUzV5MbWL9dHtxZGDAgMBAAECggEAFA/oFpGV3RsD6EWOwdVHpLbS9umLxoLHLx9Ra0/8xk763P4RS+bTE5p7fgFv714R69TdA8a9xc9DjekyVl6Ncfz+KNMF0u2+GKiZ6+p5y3M7cVUk0ovz6eGMPX3PpvkbmAKkkj4ntj1eEy3DQ7yZ2DoT+2dqQLzvFzaVlAB6v+OoCafW+mLNhSOohOmDP+hoLBv2jagTOfkD6nJkDh3++w6C8gUGv5fnUFKHhehwj/wXbtYiYYNuQFSe9DNQRg21yIr+rdhGoNR81uryWHdsuooKXYKZr1zCvJS/d1fMPj372tRACIEBGkkGuBmjzXEez1XypvjSC+KjmT3Zif7z8QKBgQDbIthfmArG6JMpvy3/WczAX0BHVQ5XK7Qh+70SWnniF2pk4x+zy2RZLzjy7szvF1g1i/SXXsaI1xymLA1xcOcEQlvWv47fjooUXgmNBHtKktDAVpBe1swEbPCAFItpynPYwSipZdIFIk1glCHOuOqjpvm0thriyJTDtFKTloq8+wKBgQC8ZXFBqFZNGg8wmLwrESVBgcHH3rNuK6niciQpb0WyMqeK9wHGKHGntvwCRMMcQrDg7asBE4so48h/q9R9xV+vNbAkv91aXBAgzx/EbAtODgQTNF60k91NT0rkDth0CjGb8LHM52XB1fnKMWHVlMvnyRrcIHXllf8FgI2Fn1bHGQKBgQDBnfMR23PCNaI5Y4rPsFdBradMn3FRQfMhh5yRx9EjG89MnoTXRiE+z4OA2c/GfJjajvMof3vpUi8k/41NKxVi5QLiJlSlX/rObhwANfJ9fGTnXFSpBx4x1tNUR1K6wT9ER76WlblQAfPeHmQUk7v1psXAjpoIwHL4y62ea4ff2wKBgQCFRxJ/S3J6KxRR4ctEgGWl2QDYv7CaIOOXIf55HZHlxbYHNkUYBWaaKnZPuIt7A6cUCK7wHP5WmAYwY8P4kdfmIIoTBXS3xudV/pFPqMu6lWnGmEbjYrOtTIoDmokAVnHQCtAN0CmJnjGPG65FpXU27WtGDOS63YlDQDVeMWH3iQKBgQCPDL9a1YZA+6Y8wVbCVkuj3bWuIx1DL7AzIbrHzib1lfMXzjumVlL+lgigna4xI4HphwMJEgGKCUYKA6JP55pSJKmptAXA6Uc4PUXEI0fHSvHeX94qEtKVGL16PLRpAZx9WqKQcmNH4oebsH/qO5jdbLbY1i++P0IwyTjd5rlsoQ==";

        String appId = "test";
        String aesKey = "0123456789abcdef";

        List<String> list = new ArrayList<>();
        list.add("test1");
        list.add("test2");


        Map<String, String> map = new HashMap<>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        List<Map<String, String>> list2 = new ArrayList<>();
        list2.add(map);
        list2.add(map);

        Map<String, String> map2 = new HashMap<>();
        map2.put("test", "test");

        //测试参数
        Map<String, Object> params = new HashMap<>();
        params.put("uuid", "0661f4f7-f56d-47b2-b996-e695d210747a");
        params.put("integer", 1);
        params.put("BigDecimal", new BigDecimal(1));
        params.put("boolean", true);
        params.put("map", map2);
        params.put("list", list);
        params.put("list2", list2);
        params.put("LocalDate", LocalDate.of(2024, 10, 1));

        //将参数按字符串进行排序
        String signatureStr = signatureStr(JSON.toJSONString(params));
        log.info("签名字符串：{}", signatureStr);
        //根据参数排序再拼接到签名字符串里面
        String toSignStr = appId + aesKey + signatureStr;

        //生成签名
        String sign = RSAUtil.buildRSASignByPrivateKey(toSignStr, privateKey);
        log.info("签名：{}", sign);

        //测试验证签名
        boolean isValid = RSAUtil.verifySignStrByPublicKey(toSignStr, publicKey, sign);
        log.info("验证签名：{}", isValid);
    }

}
